package com.chuangke.sinotrukbudget.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chuangke.admin.model.SysDept;
import com.chuangke.admin.model.SysDict;
import com.chuangke.admin.model.SysUser;
import com.chuangke.admin.service.SysDeptService;
import com.chuangke.admin.service.SysDictService;
import com.chuangke.admin.service.SysUserService;
import com.chuangke.core.dao.dao.SqlExecutorMapper;
import com.chuangke.flow.domain.FlowMdNodeOrder;
import com.chuangke.flow.enums.FlowNodeStatusEnum;
import com.chuangke.flow.service.MdFlowService;
import com.chuangke.sinotrukbudget.consts.BudgetContanst;
import com.chuangke.sinotrukbudget.model.BudgetAccount;
import com.chuangke.sinotrukbudget.model.BudgetBpcPlan;
import com.chuangke.sinotrukbudget.sdao.BudgetBpcPlanDaoService;
import com.chuangke.sinotrukbudget.service.BudgetAuditProgressMonitorService;

@Service
public class BudgetAuditProgressMonitorServiceImpl implements BudgetAuditProgressMonitorService {

	@Autowired
	private MdFlowService mdFlowService ;

	@Autowired
	private SysUserService sysUserService;
	@Autowired
	private SysDeptService sysDeptService;
	@Autowired
	private SysDictService sysDictService;
	
	@Autowired
	private SqlExecutorMapper sqlExecutorMapper ;

	@Autowired
	private BudgetBpcPlanDaoService budgetBpcPlanDaoService;
	
	private List<Map<String, Object>> findNodeCount(){
		StringBuffer sql = new StringBuffer() ;
		sql.append("select node_id ,count(distinct t_category,t_entity,t_account,handle_time) count from (");
		sql.append("	select a.node_id,a.order_id,b.t_category,b.t_entity,b.t_account,b.handle_time");
		sql.append("	from flow_ru_task a,budget_bpc_plan b ");
		sql.append("	where a.order_id=b.id and a.status='1' and a.flow_id in(select id from flow_ru_flow where md_flow_id='"+BudgetContanst.BUDGET_FLOW_ID+"' ) ");
		sql.append(" and b.account_type = 'C' ") ;
		sql.append(") node_count group by node_id");
		return sqlExecutorMapper.select(sql.toString()) ;
	}

	@Override
	public List<Map<String, Object>> progressSummary() {
		List<FlowMdNodeOrder> orderList = mdFlowService.getNodeListByOrder(BudgetContanst.BUDGET_FLOW_ID) ;
		
		List<Map<String, Object>> taskList = findNodeCount() ;
		
		Map<Object, Object> taskMap = taskList.stream().collect(Collectors.toMap(task -> task.get("node_id"), a -> a));

		List<Map<String, Object>> list = new ArrayList<>();
		for (FlowMdNodeOrder node : orderList) {
			Map<String, Object> map = new HashMap<>();
			map.put("node_id", node.getNodeIdList());
			map.put("node_title", node.getTitle());
			map.put("count", getNodeCount(node.getNodeIdList(),taskMap));
			map.put("order", node.getOrder());

			list.add(map);
		}

		list = list.stream().sorted(Comparator.comparing(map -> (Integer) map.get("order")))
				.collect(Collectors.toList());

		return list;
	}
	
	@SuppressWarnings("unchecked")
	private int getNodeCount(Set<String> nodes,Map<Object, Object> taskMap) {
		if(CollectionUtils.isEmpty(nodes)) {
			return 0 ;
		}
		
		BigDecimal sum = new BigDecimal("0") ;
		for(String nodeId: nodes) {
			Map<String, Object> task = (Map<String, Object>) taskMap.get(nodeId);
			if(task == null || task.get("count") == null) {
				continue ;
			}
			sum = sum.add(new BigDecimal(task.get("count").toString())) ;
		}
		return sum.intValue() ;
	}

	private String getNodeAppendSql(List<String> nodeIdList) {
		StringBuffer sql = new StringBuffer() ;
		sql.append("'").append(String.join("','", nodeIdList)).append("'") ;
		return sql.toString() ;
	}
	
	@Override
	public List<Map<String, Object>> progressDetailByOrderDept(List<String> nodeIdList) {
		if(CollectionUtils.isEmpty(nodeIdList)) {
			return new ArrayList<>() ;
		}
		QueryWrapper<BudgetBpcPlan> qw = new QueryWrapper<>();
		qw.select("t_category,t_entity,count(distinct t_category,t_entity,t_account,handle_time) count") ;
		qw.groupBy("t_category,t_entity,handle_time");
		qw.inSql("id",
				"select order_id from flow_ru_task where status = '" + FlowNodeStatusEnum.unhandle.getCode()
						+ "' and node_id in (" + getNodeAppendSql(nodeIdList) + ") and flow_id in(SELECT id FROM flow_ru_flow where md_flow_id='"
						+ BudgetContanst.BUDGET_FLOW_ID + "')");
		qw.lambda().eq(BudgetBpcPlan::getAccountType, BudgetAccount.ACCOUNT_TYPE_CW) ;
		Map<String, SysDept> deptMap = sysDeptService.findMap();
		Map<String, SysDict> categoryMap = sysDictService.findMap(BudgetContanst.DICT_TYPE_CATEGORY) ;
		List<Map<String, Object>> list = budgetBpcPlanDaoService.listMaps(qw);
		list.forEach(data -> {
			data.put("t_category_name", categoryMap.get(data.get("t_category")) == null ? ""
					: categoryMap.get(data.get("t_category")).getName());
			data.put("t_entity_name",
					deptMap.get(data.get("t_entity")) == null ? "" : deptMap.get(data.get("t_entity")).getName());
		});

		return list;
	}
	
	private List<Map<String, Object>> findAuditUserCount(List<String> nodeIdList){
		StringBuffer sql = new StringBuffer() ;
		sql.append("select user_id,count(distinct t_category,t_entity,t_account,handle_time) count from ( ") ;
		sql.append("	select a.user_id,a.order_id,b.t_category,b.t_entity,b.t_account,b.handle_time ") ;
		sql.append("	from flow_ru_task a,budget_bpc_plan b ") ;
		sql.append("	where a.order_id=b.id and a.status='1' and a.node_id in (" + getNodeAppendSql(nodeIdList)+ ") ") ;
		sql.append("	and a.flow_id in(select id from flow_ru_flow where md_flow_id='1034215253484765184' )") ;
		sql.append(" and b.account_type = 'C' ") ;
		sql.append(") node_count group by user_id ") ;
		return sqlExecutorMapper.select(sql.toString()) ;
	}

	@Override
	public List<Map<String, Object>> progressDetailByAuditUser(List<String> nodeIdList) {
//		QueryWrapper<FlowRuTask> qw = new QueryWrapper<FlowRuTask>();
//		qw.select("user_id,count(1) count").groupBy("user_id").eq("status", FlowNodeStatusEnum.unhandle.getCode())
//				.eq("node_id", nodeId)
//				.inSql("flow_id", "SELECT id FROM flow_ru_flow where md_flow_id='" + budget_flow_id + "'");
//		List<Map<String, Object>> list = flowRuTaskService.listMaps(qw);
		List<Map<String, Object>> list = findAuditUserCount(nodeIdList) ;
		Map<String, SysUser> userMap = sysUserService.findMap();
		list.forEach(data -> {
			SysUser user = userMap.get(data.get("user_id"));
			if (user != null) {
				data.put("name", user.getName());
				data.put("nick_name", user.getNickName());
				data.put("dept_id", user.getDeptId());
				data.put("dept_name", user.getDeptName());
			}
		});
		return list;
	}
	
}
